using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using Common.Shared.Xml.Serialization;

namespace Common.Shared.Net {
  [XmlRoot("ProxyFactory")]
  public class ProxyFactory {
    private List<ProxyInfo> _proxies = null;

    /// <summary>
    /// Initializes a new instance of the <see cref="ProxyFactory"/> class.
    /// </summary>
    public ProxyFactory ( ) {
      _proxies = new List<ProxyInfo> ( );
    }

    /// <summary>
    /// Gets or sets the proxies.
    /// </summary>
    /// <value>The proxies.</value>
    [XmlElement("ProxyInfo")]
    public List<ProxyInfo> Proxies { get { return this._proxies; } set { this._proxies = value; } }

    /// <summary>
    /// Gets or sets the <see cref="Common.Shared.Net.ProxyInfo"/> at the specified index.
    /// </summary>
    /// <value></value>
    [XmlIgnore]
    public ProxyInfo this[ int index ] {
      get { return this.Proxies[ index ]; }
      set { this.Proxies[ index ] = value; }
    }

    /// <summary>
    /// Gets or sets the <see cref="Common.Shared.Net.ProxyInfo"/> with the specified name.
    /// </summary>
    /// <value></value>
    [XmlIgnore]
    public ProxyInfo this[ string name ] {
      get { return Find ( name ); }
      set {
        ProxyInfo pi = Find ( name );
        if ( pi == null )
          Proxies.Add ( value );
        else
          pi = value;
      }
    }

    /// <summary>
    /// Finds the proxy by the specified name.
    /// </summary>
    /// <param name="name">The name.</param>
    /// <returns></returns>
    public ProxyInfo Find ( string name ) {
      foreach ( ProxyInfo pi in this._proxies ) {
        if ( string.Compare ( pi.Name, name, false ) == 0 )
          return pi;
      }
      return null;
    }

    /// <summary>
    /// Searches for the <see cref="Common.Shared.Net.ProxyInfo">ProxyInfo</see> by name and returns the index of the object. If it is not found returns -1
    /// </summary>
    /// <param name="name">The name.</param>
    /// <returns></returns>
    public int IndexOf ( string name ) {
      ProxyInfo pi = Find ( name );
      if ( pi != null )
        return this.Proxies.IndexOf ( pi );
      else
        return -1;
    }

    /// <summary>
    /// Determines whether [contains] [the specified proxy].
    /// </summary>
    /// <param name="proxy">The proxy.</param>
    /// <returns>
    /// 	<c>true</c> if [contains] [the specified proxy]; otherwise, <c>false</c>.
    /// </returns>
    public bool Contains ( ProxyInfo proxy ) {
      return this.Proxies.Contains ( proxy );
    }

    /// <summary>
    /// Determines whether the proxy collection contains key.
    /// </summary>
    /// <param name="name">The name.</param>
    /// <returns>
    /// 	<c>true</c> if the proxy collection contains key; otherwise, <c>false</c>.
    /// </returns>
    public bool ContainsKey ( string name ) {
      return Find ( name ) != null;
    }



    #region Static Methods
    /// <summary>
    /// Gets a default proxy.
    /// </summary>
    /// <returns></returns>
    public static WebProxy GetDefaultProxy ( ) {
      return new WebProxy();
    }

    /// <summary>
    /// Sets the creadentials.
    /// </summary>
    /// <param name="proxy">The proxy.</param>
    /// <param name="user">The user.</param>
    /// <param name="password">The password.</param>
    /// <param name="domain">The domain.</param>
    /// <param name="uri">The URI.</param>
    private static void SetCreadentials ( IWebProxy proxy, string user, string password, string domain, string uri ) {
      CredentialCache cCache = new CredentialCache ( );
      NetworkCredential credential = null;
      if ( string.IsNullOrEmpty(domain) )
        credential = new NetworkCredential ( user, password );
      else 
        credential = new NetworkCredential ( user, password, domain );
      cCache.Add ( new Uri ( uri ), "Negotiate", credential );
      proxy.Credentials = credential;
    }

    /// <summary>
    /// Creates the specified proxy.
    /// </summary>
    /// <param name="proxyServer">The proxy server.</param>
    /// <param name="proxyPort">The proxy port.</param>
    /// <param name="bypassLocal">if set to <c>true</c> [bypass local].</param>
    /// <returns></returns>
    public static WebProxy Create ( string proxyServer, int proxyPort, bool bypassLocal ) {
      WebProxy proxy = new WebProxy ( proxyServer, proxyPort );
      proxy.BypassProxyOnLocal = bypassLocal;
      return proxy;
    }

    /// <summary>
    /// Creates the specified domain.
    /// </summary>
    /// <param name="domain">The domain.</param>
    /// <param name="userId">The user id.</param>
    /// <param name="password">The password.</param>
    /// <param name="proxyName">Name of the proxy.</param>
    /// <param name="proxyPort">The proxy port.</param>
    /// <param name="bypassLocal">if set to <c>true</c> [bypass local].</param>
    /// <param name="uri">The URI.</param>
    /// <returns></returns>
    public static WebProxy Create ( string domain, string userId, string password, string proxyServer, int proxyPort, bool bypassLocal, string uri ) {
      WebProxy proxy = Create ( proxyServer, proxyPort, bypassLocal );
      SetCreadentials ( proxy, userId, password, domain, uri );
      return proxy;
    }

    /// <summary>
    /// Creates the specified proxy info.
    /// </summary>
    /// <param name="proxyInfo">The proxy info.</param>
    /// <param name="uri">The URI.</param>
    /// <returns></returns>
    public static WebProxy Create ( ProxyInfo proxyInfo, string uri ) {
      if ( !proxyInfo.OverrideDefaultProxy )
        return GetDefaultProxy ( );

      if ( !proxyInfo.RequiresLogin )
        return Create ( proxyInfo.ProxyServer, proxyInfo.ProxyPort, proxyInfo.BypassLocal );

      return Create ( proxyInfo.Domain, proxyInfo.Username, proxyInfo.Password, proxyInfo.ProxyServer, proxyInfo.ProxyPort, proxyInfo.BypassLocal, uri );
    }

    public static ProxyFactory CreateFromXml ( FileInfo xmlFile ) {
      return XmlSerializer<ProxyFactory>.Deserialize ( xmlFile );
    }

    public static ProxyFactory CreateFromXml ( Uri xmlUri ) {
      return XmlSerializer<ProxyFactory>.Deserialize ( xmlUri );
    }

    public static ProxyFactory CreateFromXml ( Stream stream ) {
      return XmlSerializer<ProxyFactory>.Deserialize ( stream );
    }

    public static ProxyFactory CreateFromXml ( XmlDocument doc ) {
      return XmlSerializer<ProxyFactory>.Deserialize ( doc );
    }

    #endregion
  }


}
